package b3.model
{
	import b3.config.*;
	import b3.net.*;
	import b3.widget.*;
	import b3.widget.basic.*;
	
	import flash.geom.Point;
	import flash.utils.*;
	
	public class TownModel extends Model
	{
		public var ownerId:int;
		
		public var townIndex:int;
		//{id => building}
		public var buildings:Object;
		//{posX, posY = > building} 
		public var indexMap:Object;
		
		public function TownModel()
		{
			buildings = new Object();
			ownerId = -1;
			indexMap = new Object();
		}
		
		public function loadBuildings(force:Boolean = false):void
		{
			var serverRequest:ServerRequest = new ServerRequest(ServerEvent.GET_BUILDINGS, {ownerId:ownerId});
			serverRequest.setHandleFunc(handleLoadBuildings);
			serverRequest.post(force);
		}
		
		public function handleLoadBuildings(data:Object):void
		{
			buildings = new Object();
			indexMap = new Object();
			var buildingInfo:Object = data['buildingInfo'];
			for (var s:String in buildingInfo)
			{
				var buildingModel:BuildingModel = createBuilding(buildingInfo[s]);
				buildings[s] = buildingModel;
				addMapPts(buildingModel.getPts(), buildingModel.id);
			}
			dispatchEvent(new ModelEvent(ModelEvent.REFRESH));
			var pm:PlayerManager = PlayerManager.getInstance();
			//访问好友
			if (ownerId != pm.myUserId)
			{
				pm.me.loadbyObject(data['userInfo']);
				data['visitFriend'] = true;
			}
			//发布事件
			var event:ModelEvent = new ModelEvent(ModelEvent.SWITCH_PLAYER);
			event.data = data; 
			pm.dispatchEvent(event);
		}
		
		public function checkPosAvailable(building:BuildingModel):Boolean
		{
			var availablePts:Array = getAvailablePoints(building.buildingIndex);
			var pts:Array = building.getPts();
			var pointNum:int = 0;
			for (var i:int = 0;i< pts.length;i++)
			{
				for(var j:int = 0;j < availablePts.length; j++)
				{
					if ((pts[i] as Point).equals(availablePts[j] as Point))
					{
						pointNum++;
						break;
					}	
				}
			}
			return pointNum == pts.length;
		}
		
		//增加建筑
		public function addBuilding(building:BuildingModel, force:Boolean = false):void
		{
			addMapPts(building.getPts(), building.id);
			var me:Player = PlayerManager.getInstance().me;
			var buildingConfig:BuildingConfig = Config.buildingConfigs[building.buildingIndex];
			var serverRequest:ServerRequest = new ServerRequest(ServerEvent.ADD_BUILDINGS, {building:building,   
				vitalityCost:buildingConfig.vitalityCost, vitalityMax: me.vitalityMax});
			serverRequest.setHandleFunc(handleAddBuilding);
			serverRequest.post(force);
		}
		
		public function handleAddBuilding(data:Object):void
		{
			if (data['err'] == 0)
			{
				//移除重叠模型
				var removeIds:Array = data["removeIds"];
				if (removeIds != null)
				{
					for (var i:int = 0; i < removeIds.length; i++)
					{
						removeBuildingModel(removeIds[i]);
					}
				}
				//增加建筑模型
				var building:BuildingModel = createBuilding(data["buildingInfo"]);
				building.locatedFlag = true;
				buildings[building.id] = building;
				addMapPts(building.getPts(), building.id);
				//发布建筑改变信息
				var event:ModelEvent = new ModelEvent(ModelEvent.ADD_BUILDING);
				event.data = data;
				dispatchEvent(event);
			}
			else
			{
				var popMessage:PopMessage; 
				if (data['err'] == 100)
				{
					popMessage = new PopMessage("同一绿化在同一街区最多只能有一个！", 0xFF0000);
				}
				else if (data['err'] == 101)
				{
					popMessage = new PopMessage("同一奇迹在同一街区最多只能有一个！", 0xFF0000);
				}
				else
				{
					popMessage = new PopMessage("建设失败！请重试", 0xFF0000);
				}
				WidgetManager.getInstance().popOut([popMessage]);
			}
		}
		
		//重建（自己重建或者好友协助）
		public function rebuild(building:BuildingModel, force:Boolean = false):void
		{
			var serverRequest:ServerRequest = new ServerRequest(ServerEvent.REBUILD, {building:building});
			serverRequest.setHandleFunc(handleRebuild);
			serverRequest.post(force);
		}
		
		public function handleRebuild(data:Object):void
		{
			if (data['err'] == 0)
			{ 
				//更新建筑模型
				var building:BuildingModel = buildings[data["buildingInfo"]["id"]];
				if (building == null)
				{
					building = createBuilding(data["buildingInfo"]);
					building.locatedFlag = true;
					buildings[building.id] = building;
				}
				else
				{
					building.loadbyObject(data["buildingInfo"]);
				}
			}
			

			//协助别人建设
			var me:Player = PlayerManager.getInstance().me;
			if (building.ownerId != me.userId)
				me.taskList.finishTask(TaskConfig.ID_ASSIST_FRIEND);
			//发布建筑改变信息
			var event:ModelEvent = new ModelEvent(ModelEvent.REFRESH_BUILDING);
			event.data = data;
			dispatchEvent(event);
		}
		
		private function addMapPts(pts:Array, buildingId:int):void
		{
			for (var i:int = 0; i < pts.length; i++)
			{
				indexMap[pts[i].x+"_"+pts[i].y] = buildingId;
			}
		}
		
		//删除建筑
		public function removeBuilding(buildId:int, force:Boolean = false):void
		{
			var serverRequest:ServerRequest = new ServerRequest(ServerEvent.REMOVE_BUILDING, {buildingId: buildId});
			serverRequest.setHandleFunc(handleRemoveBuilding);
			serverRequest.post(force);
		}
		
		public function handleRemoveBuilding(data:Object):void
		{
			var building:BuildingModel = createBuilding(data["buildingInfo"]);
			removeBuildingModel(building.id);
			//刷新视图
			var event:ModelEvent = new ModelEvent(ModelEvent.REMOVE_BUILDING);
			event.data = data;
			dispatchEvent(event);
		}
		
		//删除建筑模型
		private function removeBuildingModel(buildId:int):void
		{
			var building:BuildingModel = buildings[buildId];
			var arr:Array = building.getPts();
			for (var i:int = 0;i<arr.length;i++)
			{
				delete indexMap[arr[i].x +"_" +arr[i].y];
			}
			delete buildings[building.id];
		}
		
		/**
		 * 攻击建筑
		 */ 
		public function attackBuilding(rocket:BuildingModel, targetBuilding:BuildingModel):void
		{
			var serverRequest:ServerRequest = new ServerRequest(ServerEvent.ATTACK_BUILDING, {targetBuilding: targetBuilding, rocket: rocket});
			serverRequest.setHandleFunc(handleAttackBuilding);
			serverRequest.post();
		}
		
		/**
		 * 处理导弹袭击的事件数据
		 */ 
		private function handleAttackBuilding(data:Object):void
		{
			//攻击成功
			if (data["err"] == 0)
			{
				//移除己方导弹
				var me:Player = PlayerManager.getInstance().me;
				me.townModel.removeBuildingModel(data['rocketId']);
				//更新建筑模型
				var building:BuildingModel = buildings[data["buildingInfo"]["id"]];
				if (building == null)
				{
					building = createBuilding(data["buildingInfo"]);
					building.locatedFlag = true;
					buildings[building.id] = building;
				}
				else
				{
					building.loadbyObject(data["buildingInfo"]);
				}
			}
			//发出事件
			var modelEvent:ModelEvent = new ModelEvent(ModelEvent.ATTACK_BUILDING);
			modelEvent.data = data;
			dispatchEvent(modelEvent);
		}
		
		//更新区域
		public function attackArea(data:Object):void
		{
			//更新建筑
		 	for (var idStr:String in data['buildings'])
		 	{
		 		 handleRebuild(data['buildings'][idStr]);
		 	}
			//发出事件
			var modelEvent:ModelEvent = new ModelEvent(ModelEvent.ATTACK_AREA);
			modelEvent.data = data;
			dispatchEvent(modelEvent);
		} 

		public static function createBuilding(data:Object):BuildingModel
		{
			var building:BuildingModel = new BuildingModel();
			building.loadbyObject(data);
			return building;
		}
		
		public function getAvailablePoints(buildingIndex:int):Array
		{
			var buildingConfig:BuildingConfig = Config.buildingConfigs[buildingIndex];
			var requireBuildings:Array = buildingConfig.nearRequire;
			var result:Array = new Array();
			var player:Player = PlayerManager.getInstance().players[ownerId];
			var townConfig:TownConfig = Config.townConfigs[0];
			for (var i:int = 0; i < townConfig.sectionConfigs.length; i++)
			{
				var sectionConfig:SectionConfig = townConfig.sectionConfigs[i];
				if (player.historyMaxPopulation >= sectionConfig.requirePopulation)
				{
					var arr:Array = sectionConfig.sectionPoints;
					for (var j:int = 0, len:int = arr.length;  j < len; j++)
					{
						if (PlayerManager.getInstance().myUserId != ownerId && indexMap[arr[j].x+"_"+arr[j].y] != null)
							continue;
						if (checkNearBuilding(arr[j].x,arr[j].y,requireBuildings))
						{
							result.push(arr[j]);
						}
					}
				}
			}
			return result;
		}
		
		private function checkNearBuilding(x:int,y:int,buildingIndexs:Array):Boolean
		{
			if (buildingIndexs == null || buildingIndexs.length == 0)
				return true;
			var result:Boolean = true;
			for (var i:int = 0,len:int = buildingIndexs.length; i<len; i++)
			{
				var building:BuildingModel = buildings[indexMap[(x - 1)+"_"+(y)]];
				//上
				if (building != null && building.buildingIndex == buildingIndexs[i])
				{
					continue;
				}
				building = buildings[indexMap[(x + 1)+"_"+(y)]];
				if (building != null && building.buildingIndex == buildingIndexs[i])
				{
					continue;
				}
				building = buildings[indexMap[(x)+"_"+(y - 1)]];
				if (building != null && building.buildingIndex == buildingIndexs[i])
				{
					continue;
				}
				building = buildings[indexMap[(x)+"_"+(y + 1)]];
				if (building != null && building.buildingIndex == buildingIndexs[i])
				{
					continue;
				}
				return false;
			}
			return result;
		}
		
		public function getNearGreenSumNum(x:int, y:int, isoWidth:int = 1, isoHeight:int = 1):int
		{
			var greenSum:int = 0;
			greenSum += getGreenNum(x-1, y-1);
			greenSum += getGreenNum(x-1, y+isoHeight);
			greenSum += getGreenNum(x+isoWidth, y-1);
			greenSum += getGreenNum(x+isoWidth, y+isoHeight);
			var i:int = 0;
			for (i = 0; i<isoWidth; i++)
			{
				greenSum += getGreenNum(x+i, y-1);
				greenSum += getGreenNum(x+i, y+isoHeight);
			}
			for (i = 0; i<isoHeight; i++)
			{
				greenSum += getGreenNum(x-1, y+i);
				greenSum += getGreenNum(x+isoWidth, y+i);
			}
			return greenSum;
		}
		
		public function getGreenNum(x:int, y:int):int
		{
			var greenNum:int = 0;
			var buildingConfig:BuildingConfig;
			var building:BuildingModel = getBuildingByPos(x, y);
			if (building != null)
			{
				buildingConfig = Config.buildingConfigs[building.buildingIndex];
				if (buildingConfig.type == BuildingConfig.GREEN)
				{
					greenNum += building.population;
				}
			}
			return greenNum;
		}
		
		public function getBuildingByPos(x:int,y:int):BuildingModel
		{
			var building:BuildingModel = buildings[indexMap[x + "_" + y]];
			return building;
		}
		
		public function getBuildingNum(buildingIndex:int):int
		{
  			var buildingNum:int = 0;
  			for (var idStr:String in buildings)
  			{
  				var buildingModel:BuildingModel = buildings[idStr];
  				if (buildingModel.buildingIndex == buildingIndex)
  				{
  					buildingNum++;
  				}
  			}
  			return buildingNum;
		}
	}
}